package com.dayu.frame;

import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.engine.EngineFileType;
import cn.smallbun.screw.core.engine.EngineTemplateType;
import cn.smallbun.screw.core.execute.DocumentationExecute;
import cn.smallbun.screw.core.process.ProcessConfig;
import com.dayu.helper.ConfigHelper;
import com.dayu.helper.EntryHelper;
import com.mysql.cj.util.StringUtils;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import javax.sql.DataSource;
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class DocFrame extends JFrame {
    private DefaultListModel<JCheckBox> tableListModel;
    public DocFrame() {

        setTitle("ScrewDataBaseDoc-GUI");
        setIconImage(Toolkit.getDefaultToolkit().getImage(getClass().getResource("/icon.png")));
        getRootPane().setBorder(new LineBorder(Color.getColor("#7a8a99"), 1, true));
        setSize(450, 530);
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int x = (screenSize.width - getWidth()) / 2;
        int y = (screenSize.height - getHeight()) / 2;
        setLocation(x, y);
        setUndecorated(true);
        getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
        setLayout(null);

        //第一行
        JLabel lbDataBaseUrl = new JLabel("地址：", SwingConstants.LEFT);
        lbDataBaseUrl.setBounds(10, 10, 40, 20);
        add(lbDataBaseUrl);

        JTextField tfDataBaseUrl = new JTextField();
        tfDataBaseUrl.setBounds(60, 10, 170, 20);
        tfDataBaseUrl.setText("请先设置连接");
        tfDataBaseUrl.setEnabled(false);
        EntryHelper.addPropertyChangeListener(evt -> {
            if ("jdbcUrl".equals(evt.getPropertyName())) {
                tfDataBaseUrl.setText((String) evt.getNewValue());
            }
        });
        add(tfDataBaseUrl);

        JButton btnSetConnect = new JButton("设置连接");
        btnSetConnect.setBounds(240, 10, 100, 20);
        add(btnSetConnect);
        btnSetConnect.addActionListener(e -> openSetDBFrame());

        JButton btnHelp = new JButton("使用帮助");
        btnHelp.setBounds(350,10,90,20);
        add(btnHelp);
        btnHelp.addActionListener(e -> JOptionPane.showMessageDialog(null,
                "\uD83D\uDE01使用帮助：\n" +
                        "1、输入MySQL的数据地址、用户名、密码，点击[获取数据库]；\n" +
                        "2、获取成功后在数据库列表中选中想要导出的数据库；\n" +
                        "3、点击[加载表]，在列表中勾选想要导出的表；\n" +
                        "4、选择好表之后，输入路径（可以通过浏览和输入）；\n" +
                        "5、最后输入文件名等信息后，点击[生成并保存]\n" +
                        "6、等待生成完成之后会自动打开导出的路径。\n" +
                        "\n" +
                        "全选、反选：全部选择、反向选择；\n" +
                        "只选：只选择有说明的表；\n" +
                        "前缀为、后缀为、选择：按照输入的前后缀选择符合要求的表；\n" +
                        "\n" +
                        "使用screw生成，信息依赖于字段、表的描述。\n",
                "使用帮助",
                JOptionPane.INFORMATION_MESSAGE));

        // 第二行
        JLabel lbDataBase = new JLabel("数据库：", SwingConstants.LEFT);
        lbDataBase.setBounds(10, 40, 55, 20);
        add(lbDataBase);

        JComboBox<String> cbDataBase = new JComboBox<>(new String[]{"无"});
        cbDataBase.setRenderer(new ToolTipRenderer());
        cbDataBase.setBounds(60, 40, 170, 20);

        cbDataBase.setEditable(false);
        add(cbDataBase);

        JButton btnConnect = new JButton("获取数据库");
        btnConnect.setBounds(240, 40, 100, 20);
        add(btnConnect);
        btnConnect.addActionListener(e -> {
            cbDataBase.removeAllItems();
            try{
                List<String> dbList = EntryHelper.QueryDataBaseList();
                for(String str: dbList)
                    cbDataBase.addItem(str);
                JOptionPane.showMessageDialog(null, "获取完成，请选择一个数据库继续操作。", "获取成功", JOptionPane.PLAIN_MESSAGE);
            }catch (Exception ex){
                JOptionPane.showMessageDialog(null, "获取失败：" + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
            }
        });

        JButton btnLoadTables = new JButton("加载表");
        btnLoadTables.setBounds(350, 40, 90, 20);
        add(btnLoadTables);
        btnLoadTables.addActionListener(e -> {
            String dbName = (String) cbDataBase.getSelectedItem();
            if (dbName == null) {
                JOptionPane.showMessageDialog(null, "请选择一个数据库！", "错误", JOptionPane.ERROR_MESSAGE);
            } else {
                try {
                    tableListModel.removeAllElements();
                    List<String> tableList = EntryHelper.QueryAllTable(dbName);
                    for (String str : tableList) {
                        JCheckBox checkBox = new JCheckBox(str, true);
                        tableListModel.addElement(checkBox);
                    }
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(null, "加载失败：" + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                }
            }
        });

        tableListModel = new DefaultListModel<>();
        JList<JCheckBox> tableList = new JList<>(tableListModel);
        tableList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        tableList.setBackground(Color.decode("#eeeeee"));
        tableList.setCellRenderer(new CheckBoxListRenderer(tableList));

        tableList.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                int index = tableList.locationToIndex(e.getPoint());
                if (index != -1) {
                    JCheckBox checkBox = tableListModel.getElementAt(index);
                    checkBox.setSelected(!checkBox.isSelected());
                    tableList.repaint(tableList.getCellBounds(index, index));
                }
            }
        });

        //列表
        JScrollPane scrollPane = new JScrollPane(tableList);
        scrollPane.setBounds(10, 70, 350, 300);
        add(scrollPane);

        JButton btnInvertSelection = new JButton("全选");
        btnInvertSelection.setBounds(370, 70, 70, 20);
        add(btnInvertSelection);
        btnInvertSelection.addActionListener(e -> {
            for (int i = 0; i < tableListModel.getSize(); i++) {
                JCheckBox checkBox = tableListModel.getElementAt(i);
                checkBox.setSelected(true);
            }
            tableList.repaint();
        });
        JButton btnAllSelection = new JButton("反选");
        btnAllSelection.setBounds(370, 100, 70, 20);
        add(btnAllSelection);
        btnAllSelection.addActionListener(e -> {
            for (int i = 0; i < tableListModel.getSize(); i++) {
                JCheckBox checkBox = tableListModel.getElementAt(i);
                checkBox.setSelected(!checkBox.isSelected());
            }
            tableList.repaint();
        });

        JButton btnHasSelection = new JButton("只选");
        btnHasSelection.setBounds(370, 130, 70, 20);
        add(btnHasSelection);
        btnHasSelection.addActionListener(e -> {
            for (int i = 0; i < tableListModel.getSize(); i++) {
                JCheckBox checkBox = tableListModel.getElementAt(i);
                checkBox.setSelected(checkBox.getText().split(" - ").length>=2);
            }
            tableList.repaint();
        });

        JLabel lbPrefix = new JLabel("前缀为：", SwingConstants.LEFT);
        lbPrefix.setBounds(370, 160, 70, 20);
        add(lbPrefix);
        JTextField tfPrefixText = new JTextField();
        tfPrefixText.setBounds(370, 180, 70, 20);
        tfPrefixText.setText("");
        add(tfPrefixText);

        JLabel lbSuffix = new JLabel("后缀为：", SwingConstants.LEFT);
        lbSuffix.setBounds(370, 200, 70, 20);
        add(lbSuffix);
        JTextField tfSuffixText = new JTextField();
        tfSuffixText.setBounds(370, 220, 70, 20);
        tfSuffixText.setText("");
        add(tfSuffixText);
        JButton btnEndIsSelection = new JButton("选择");
        btnEndIsSelection.setBounds(370, 240, 70, 20);
        add(btnEndIsSelection);
        btnEndIsSelection.addActionListener(e -> {
            String start = tfPrefixText.getText();
            String end = tfSuffixText.getText();
            for (int i = 0; i < tableListModel.getSize(); i++) {
                JCheckBox checkBox = tableListModel.getElementAt(i);
                String now = checkBox.getText().split(" - ")[0];
                boolean seleced = false;

                if(!StringUtils.isNullOrEmpty(start) && !StringUtils.isNullOrEmpty(end)){
                    seleced = now.startsWith(start) && now.endsWith(end);
                }else if(StringUtils.isNullOrEmpty(start) && !StringUtils.isNullOrEmpty(end)){
                    seleced = now.endsWith(end);
                }else if(!StringUtils.isNullOrEmpty(start) && StringUtils.isNullOrEmpty(end)){
                    seleced = now.startsWith(start);
                }
                checkBox.setSelected(seleced);
            }
            tableList.repaint();
        });




        //第三行
        JLabel lbOutputFolder = new JLabel("输出路径：", SwingConstants.LEFT);
        lbOutputFolder.setBounds(10, 380, 70, 20);
        add(lbOutputFolder);

        JTextField tfOutputFolder = new JTextField();
        tfOutputFolder.setBounds(80, 380, 300, 20);
        add(tfOutputFolder);

        JButton btnSelectFolder = new JButton("浏览");
        btnSelectFolder.setBounds(380, 380, 60, 20);
        add(btnSelectFolder);
        btnSelectFolder.addActionListener(e -> {
            JFileChooser chooser = new JFileChooser();
            chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            int returnValue = chooser.showOpenDialog(null);
            if (returnValue == JFileChooser.APPROVE_OPTION) {
                File selectedFolder = chooser.getSelectedFile();
                tfOutputFolder.setText(selectedFolder.getAbsolutePath());
            }
        });
        // 第四行
        JLabel lbFileType = new JLabel("类型：", SwingConstants.LEFT);
        lbFileType.setBounds(300, 410, 50, 20);
        add(lbFileType);

        JComboBox<String> cbFileType = new JComboBox<>(new String[]{"Word", "HTML", "Markdown"});
        cbFileType.setBounds(340, 410, 100, 20);
        cbFileType.setEditable(false);
        add(cbFileType);

        JLabel lbFileName = new JLabel("文件名称：", SwingConstants.LEFT);
        lbFileName.setBounds(10, 410, 70, 20);
        add(lbFileName);

        JTextField tfFileName = new JTextField();
        tfFileName.setBounds(80, 410, 200, 20);
        tfFileName.setText("");
        add(tfFileName);

        // 第五行
        JLabel lbDescription = new JLabel("文档描述：", SwingConstants.LEFT);
        lbDescription.setBounds(10, 440, 80, 20);
        add(lbDescription);

        JTextField tfDescription = new JTextField();
        tfDescription.setBounds(80, 440, 200, 20);
        tfDescription.setText("数据库设计文档生成");
        add(tfDescription);

        JLabel lbVersion = new JLabel("版本：", SwingConstants.LEFT);
        lbVersion.setBounds(300, 440, 80, 20);
        add(lbVersion);

        JTextField tfVersion = new JTextField();
        tfVersion.setBounds(340, 440, 100, 20);
        tfVersion.setText("1.0.0");
        add(tfVersion);


        // 生成按钮
        JButton btnGenerate = new JButton("生成并保存");
        btnGenerate.setBounds(10, 470, 430, 30);
        add(btnGenerate);
        btnGenerate.addActionListener(e -> {
            // 获取选择的表
            List<String> selectedTables = new ArrayList<>();
            for (int i = 0; i < tableListModel.getSize(); i++) {
                JCheckBox checkBox = tableListModel.getElementAt(i);
                if (checkBox.isSelected()) {
                    selectedTables.add(checkBox.getText().split(" - ")[0]);
                }
            }
            if(selectedTables.isEmpty()){
                JOptionPane.showMessageDialog(null,
                        "至少选择一个表",
                        "生成失败",
                        JOptionPane.ERROR_MESSAGE);
                return;
            }
            // 输出选择的信息
            String outputFolder = tfOutputFolder.getText();
            String fileType = (String) cbFileType.getSelectedItem();
            String fileName = tfFileName.getText();
            String version = tfVersion.getText();
            String description = tfDescription.getText();

            if(outputFolder!=null && outputFolder.isEmpty()){
                JOptionPane.showMessageDialog(null,
                        "请选择输出路径",
                        "生成失败",
                        JOptionPane.ERROR_MESSAGE);
                return;
            }
            if(fileName!=null && fileName.isEmpty()){
                JOptionPane.showMessageDialog(null,
                        "请输入文件名",
                        "生成失败",
                        JOptionPane.ERROR_MESSAGE);
                return;
            }

            EngineFileType fileType1 = "HTML".equals(fileType)?EngineFileType.HTML:"Markdown".equals(fileType)?EngineFileType.MD:EngineFileType.WORD;
            GenDoc(outputFolder, fileName, fileType1, selectedTables, version, description);
        });
        add(lbFileType);

        addWindowListener(new WindowAdapter() {
            @Override
            public void windowOpened(WindowEvent e) {
                onWindowOpened();
            }
        });


    }
    // 在窗口显示后执行的逻辑
    private void onWindowOpened() {
        // 加载现有配置
        if (ConfigHelper.hasConfig()) {
            String dbType = ConfigHelper.getDbType();
            String dbUrl = ConfigHelper.getDbUrl();
            String dbUser = ConfigHelper.getDbUser();
            String dbPwd = ConfigHelper.getDbPwd();
            String dbInit = ConfigHelper.getDbInit();

            try{EntryHelper.verifyConnection(dbType, dbUrl, dbUser, dbPwd, dbInit);}catch (Exception e){}
        }
    }

    public void GenDoc(String GenUrl,
                       String GenFileName, EngineFileType fileType, List<String> tables,
                       String V, String D){
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName(EntryHelper.DriverClassName);
        hikariConfig.setJdbcUrl(EntryHelper.getJdbcUrl());
        hikariConfig.setUsername(EntryHelper.DataBaseUser);
        hikariConfig.setPassword(EntryHelper.DataBasePwd);
        //设置可以获取tables remarks信息
        hikariConfig.addDataSourceProperty("useInformationSchema", "true");
        hikariConfig.setMinimumIdle(2);
        hikariConfig.setMaximumPoolSize(5);
        DataSource dataSource = new HikariDataSource(hikariConfig);
        //生成配置
        EngineConfig engineConfig = EngineConfig.builder()
                //生成文件路径
                .fileOutputDir(GenUrl)
                //打开目录
                .openOutputDir(true)
                //文件类型
                .fileType(fileType)
                //生成模板实现
                .produceType(EngineTemplateType.freemarker)
                //自定义文件名称
                .fileName(GenFileName).build();
        //忽略表
        ArrayList<String> ignoreTableName = new ArrayList<>();
        ignoreTableName.add("test_user");
        ignoreTableName.add("test_group");
        //忽略表前缀
        ArrayList<String> ignorePrefix = new ArrayList<>();
        ignorePrefix.add("test_");
        //忽略表后缀
        ArrayList<String> ignoreSuffix = new ArrayList<>();
        ignoreSuffix.add("_test");
        ProcessConfig processConfig = ProcessConfig.builder()
                //指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时，将生成指定表，其余表不生成、并跳过忽略表配置
                //根据名称指定表生成
                .designatedTableName(tables)
                //根据表前缀生成
                .designatedTablePrefix(new ArrayList<>())
                //根据表后缀生成
                .designatedTableSuffix(new ArrayList<>())
                //忽略表名
                .ignoreTableName(ignoreTableName)
                //忽略表前缀
                .ignoreTablePrefix(ignorePrefix)
                //忽略表后缀
                .ignoreTableSuffix(ignoreSuffix).build();
        //配置
        Configuration config = Configuration.builder()
                //版本
                .version(V)
                //描述
                .description(D)
                //数据源
                .dataSource(dataSource)
                //生成配置
                .engineConfig(engineConfig)
                //生成配置
                .produceConfig(processConfig)
                .build();
        //执行生成
        new DocumentationExecute(config).execute();
    }
    private void openSetDBFrame(){
        SetDBFrame setDBFrame = new SetDBFrame(this);
        setDBFrame.setVisible(true);
    }
}
